home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Night Owl 6
/
Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso
/
029a
/
new1091.zip
/
NEW.ASM
next >
Wrap
Assembly Source File
|
1991-10-15
|
43KB
|
1,613 lines
PAGE ,132
TITLE NEW - Show New Files In Last Specified Days
SUBTTL Display new files
; SET TABS TO 8
; ;
;****************************************************************************;
; ;
; Copyright (c) John Pulliam 1989 - 1991 Version 10/15/91 ;
; ;
; For Columbia Data Product Computers and Compatibles ;
; ;
;****************************************************************************;
; ;
; This program displays a list of the files in the specified directory
; that were created since midnight of the current day, or optionally
; since midnight of any earlier day.
;
; All files with attributes of Hidden, System, Read-Only, Archive,
; Volume Label and Directory are displayed along with normal files.
;
; This program may only be used with DOS 2.0 or higher.
;
; This program is released to the Public Domain for non-commercial use
; and may be used for commercial use with permission of the author.
;
; The only allowable input commands are:
; "NEW"
;
; "NEW/x d:"
;
; "NEW/x d:file.ext", where
;
; "NEW/x d:\dir"
;
; "NEW/x d:\dir\file.ext", where
;
; "x" is the number of days prior to the current day that files
; should be searched for. The default is 0, the current day.
; "d" is the disk drive that the 'new' files will be displayed
; from.
; "file" is the name of the file to search for.
; Wild card symbols of * or ? may be used.
; "ext" is the extension of the file name to search for.
; Wild card symbols of * or ? may be used.
; "dir" is the directory on drive "d" that the 'new' files will
; be displayed from.
; The directory can not be entered without the drive.
;
;
; An ERRORLEVEL of 0 is returned if NO error occurs.
; An ERRORLEVEL of 1+ is returned if an error occurs.
;
;
; Version 10/15/91 added code to display an extension of a
; sub-directory name.
;
; Version 6/03/91 corrected a minor bug in some error messages.
;
; Version 2/12/91 of NEW was changed to allow a "file.ext" to be
; added in the command line and also display volume labels.
;
; This program is made available for use with no liability assumed by
; the author.
;
;****************************************************************************;
CSEG SEGMENT PARA PUBLIC
ASSUME CS:CSEG,DS:CSEG,ES:CSEG
ORG 100H
; Select which type of output display format is desired
DTYPE EQU 1 ; 1 = Use the dd-Mon-yy display for the dates
; ie: 24-Oct-89 for October 24, 1989
;DTYPE EQU 0 ; 0 = Use the mm-dd-yy display for the dates
; ie: 10-24-89 for October 24, 1989
; Define Some Constants
CR EQU 13 ; Carriage Return Code
LF EQU 10 ; Line Feed Code
MAXLEN EQU 65 ; Max length for any d:\dir\file spec
CMDLINE EQU 80H ; Start of command line arguments
FIRST EQU 4EH ; Find name of first disk file
NEXT EQU 4FH ; Find name of the next disk file
; File attributes used
RO EQU 01H ; Read Only attribute bit
HDN EQU 02H ; Hidden attribute bit
SYS EQU 04H ; System attribute bit
VOL EQU 08H ; Vol Label attribute bit
DIR EQU 10H ; Directory attribute bit
ARC EQU 20H ; Archive attribute bit
; Beginning Of Executable Code
NEW: MOV DX,OFFSET SMSG1 ; Display initial message
MOV AH,9
INT 21H
; Make sure that this is DOS 2.0 or higher
CALL CHKDOS ; Check DOS version
CMP AL,2 ; Want version 2.0 or higher
JGE NEW2 ; so branch if okay
; Tell User he needs a later version of DOS and quit
MOV AH,9 ; Otherwise tell user and quit
MOV DX,OFFSET ERMSG1
INT 21H
INC BYTE PTR ERRFLG
NEW1: JMP FINIS ; Quit if less than DOS 2.0
; Get the System Date from DOS
NEW2: MOV DI,OFFSET SYSDATE
CALL GET_SYSDATE
; Convert it to 1 hex word containing number of days since 1-Jan-1980
MOV SI,OFFSET SYSDATE
MOV DI,OFFSET SYSDAYS
CALL HDATE
; Get the command line arguments if any
CALL GET_ARGS ; This stores the specified drive too
JC NEW1 ; Quit if an error
CMP BYTE PTR DRIVE,' '
JNE NEW3 ; Skip if drive was in arguments
; Get the default drive & directory & put it in the message
MOV AH,19H
MOV DL,0
INT 21H ; Get the default drive
ADD AL,'A' ; Convert number to letter
MOV DRIVE,AL
NEW3: CMP BYTE PTR DIREC,0
JNZ NEW4 ; Skip if a directory was in the arguments
MOV DL,AL
SUB DL,40H ; Drive code (1 = A, etc.)
MOV AH,47H
MOV SI,OFFSET DIREC
INT 21H ; Get the default directory
; Put the drive, directory & filespec in FULLNAM too
NEW4: MOV SI,OFFSET DRIVE
MOV DI,OFFSET FULLNAM
MOV CX,MAXLEN+3
NEW5: LODSB
STOSB
AND AL,AL
LOOPNZ NEW5
DEC DI
; Here FULLNAM will ALWAYS contain at least the 'drive:\directory'
CMP BYTE PTR [DI-1],'\'
JE NEW6 ; Add '*.*' after dir\
CMP BYTE PTR HASDOT,0
JNZ NEW8 ; Add nothing after file.ext
; or else add '\*.*' after dir
MOV AL,'\' ; Add '\*.*' after filespec
STOSB
; Add '*.*' after filespec
NEW6: MOV BYTE PTR [DI],'*'
MOV BYTE PTR [DI+1],'.'
MOV BYTE PTR [DI+2],'*'
; Set the DTA to our filespec buffer
NEW8: MOV AH,1AH
MOV DX,OFFSET FSPEC
INT 21H
; Display the header info
MOV CX,80
MOV SI,OFFSET SMSG2
NEW10: LODSB
CMP AL,0 ; Don't display or count zeros
JZ NEW10
CMP AL,'$' ; Quit when '$' is found
JE NEW12
MOV DL,AL
MOV AH,2
INT 21H
LOOP NEW10
; Our compare date is set to System date minus number of days in command line
; Since the file time is not looked at, any file of the proper day will be
; a "match".
; Loop here "finding" every file, checking the date/time and display
; the file name if it was created after our COMDAYS.
NEW12: MOV CX,12 ; Clear the file name buffer for grins
MOV DI,OFFSET FILENAM
MOV AL,0
REP STOSB
; DOS stores the file name in FSPEC+30 (FILENAM label)
CALL FINDFILE ; Get the first or next file
JNC NEW13 ; Skip if file found okay
CMP AX,12H ; See if no more files
JE QUIT ; Exit if no more files
JMP FINIS ; Quit if non-existant directory
; Get the file date/time from the FCB returned by DOS
NEW13: MOV DI,OFFSET FILDATE
CALL GET_FILDATE
; Convert the file date to the number of days since 1-Jan-1980
MOV SI,OFFSET FILDATE
MOV DI,OFFSET FILDAYS
CALL HDATE
; Compare the file date/time with Comdays date/time.
MOV AX,FILDAYS ; File days since 1/1/80
CMP AX,COMDAYS ; Compare days
JL NEW16 ; Skip if file days is older
; Display the file information if we have a match
NEW14: CALL DISP ; Display the file name
INC WORD PTR TOTFILE; Increment the total number of files
; Loop for the next file
NEW16: JMP NEW12
; Exit back to DOS
QUIT: MOV SI,OFFSET TOTFILE
MOV DI,OFFSET TOTF
CALL HEX_DEC8 ; Get total files in decimal
JC FINIS
MOV SI,OFFSET TOTSIZE
MOV DI,OFFSET TOTS
CALL HEX_DEC8 ; Get total bytes in decimal
JC FINIS
CMP WORD PTR TOTFILE,1
JNE Q1
MOV BYTE PTR TOTFS,' '
Q1: MOV SI,OFFSET SMSG3 ; Display the totals
MOV CX,80
Q2: LODSB
CMP AL,0 ; Ignore null codes
JZ Q2
CMP AL,'$'
JE Q4 ; Finished if '$'
MOV DL,AL
MOV AH,2
INT 21H
LOOP Q2
; Get and display the free bytes on the drive
Q4: MOV DL,DRIVE
SUB DL,40H ; 1 = drive A, etc.
MOV SI,OFFSET FREESIZ
MOV DI,OFFSET SIZLEFT
CALL FREE_SPACE ; Get the free space
MOV SI,OFFSET SMSG4 ; Display the free bytes on the drive
MOV CX,80
Q5: LODSB
CMP AL,0 ; Ignore null codes
JZ Q5
CMP AL,'$'
JE FINIS ; Finished if '$'
MOV DL,AL
MOV AH,2
INT 21H
LOOP Q5
FINIS: MOV AH,4CH
MOV AL,ERRFLG ; Use ERRFLG for a return code
INT 21H ; Return to DOS When Finished
SUBTTL Miscellaneous Callable Routines
PAGE +
;
;****************************************************************************;
;
; DISP - Display The File Name And Information
;
; This routine assembles the information for each line to be displayed
; then writes it to the CRT.
;
; Entry: None
;
; Exit: None
;
; Alters: All registers are altered
;
;****************************************************************************;
;
DISP: MOV BYTE PTR DIRFLG,0
; Need special handling for directory names
MOV DL,FSPEC+21 ; Get the file attributes
CMP DL,DIR ; See if it a directory or subdirectory
JNE DISP6 ; Branch to display normal file name if not
; Have directory name
; Need special handling for "." & ".." directory names
MOV SI,OFFSET FILENAM
MOV DX,OFFSET DOT
CMP BYTE PTR [SI],'.'
JNE DISP1 ; Skip if not '.'
CMP BYTE PTR [SI+1],0
JE DISP4 ; Skip if not '.',0
MOV DX,OFFSET DOTDOT; Check for '..',0
CMP WORD PTR [SI+1],002EH
JE DISP4 ; Branch to display ".." directory name
; Have a subdirectory name so display it
DISP1: MOV SI,OFFSET FILENAM
MOV CX,8
DISP2: LODSB
AND AL,AL
JNZ DISP3
MOV AL,' '
DISP3: MOV DL,AL
MOV AH,2
INT 21H
LOOP DISP2
; Add a space and the sub-directory extension
MOV AH,2 ; Add a space before the extension
MOV DL,' '
INT 21H
CALL DISPEXT ; Write the extension
JMP SHORT DISP5
; Have a "." or ".." directory name
DISP4: MOV AH,9
INT 21H ; Display '.' or '..' name
DISP5: MOV DX,OFFSET DIRNAME
MOV AH,9 ; Display the '<DIR>'
INT 21H
MOV DI,OFFSET FSIZE+2
MOV CX,8
MOV AL,' '
REP STOSB ; Blank fill the file size
MOV BYTE PTR DIRFLG, 1
JMP SHORT DISP17 ; Branch to continue with the file attributes
; Display the file name
DISP6: MOV CX,8
MOV SI,OFFSET FILENAM
DISP8: LODSB
CMP AL,0 ; Quit when 0 is found
JZ DISP9
CMP AL,'.' ; Quit when '.' is found
JNE DISP10
DISP9: MOV DL,' ' ; Fill in with spaces
MOV AH,2
INT 21H
LOOP DISP9
JMP SHORT DISP13 ; Branch to display the extension
DISP10: MOV DL,AL
MOV AH,2
INT 21H
LOOP DISP8
TEST BYTE PTR FSPEC+21,VOL ; Check for Vol Label attribute
JZ DISP13 ; Skip if not volume label
MOV CX,4 ; Display up to 4 more symbols of vol label
JMP SHORT DISP14 ; Branch to display remainder of vol label
; Add a space before the extension and write the extension
DISP13: MOV AH,2 ; Add a space before the extension
MOV DL,' '
INT 21H
DISP14: CALL DISPEXT ; Write the extension
; Get the file size & update the total size
MOV SI,OFFSET FSPEC+26
MOV DI,OFFSET FSIZE+2
MOV AX,[SI] ; Keep running total of bytes
ADD WORD PTR TOTSIZE,AX
MOV AX,[SI+2] ; Upper word of total bytes
ADC WORD PTR TOTSIZE+2,AX
CALL HEX_DEC8 ; Convert the file size to decimal
; Fill in the file attributes in the message
; Attribute
; none = 0
; RO = 1
; HDN = 2
; SYS = 4
; VOL = 8
; DIR = 10
; ARC = 20
DISP17: MOV DI,OFFSET ATTS ; Point to the message buffer
MOV CX,24 ; Length of the buffer
MOV AL,' '
REP STOSB ; Clear the previous file attributes
MOV DL,FSPEC+21 ; Get the current file attributes
MOV SI,OFFSET ATT_TXT; Text string pointer
MOV DI,OFFSET ATTS ; Message buffer pointer
MOV DH,1 ; Attribute mask
DISP18: TEST DL,DH ; See if this attribute is set
JZ DISP19 ; Skip if it is not set
MOV AX,WORD PTR [SI+0]
STOSW ; Store the first two symbols
MOV AX,WORD PTR [SI+2]
STOSW ; Store the last two symbols
DISP19: ADD SI,4 ; Move text string pointer
SHL DH,1 ; Move attribute mask
CMP DH,20H ; See if this is the last one
JLE DISP18 ; Repeat until finished
; Display the file size, date, time & attributes
MOV SI,OFFSET FSIZE ; Display the file size, date & time
MOV CX,80
CMP BYTE PTR DIRFLG,0
JZ DISP22 ; Skip if not directory or subdirectory
ADD SI,6
SUB CX,6
DISP22: LODSB
CMP AL,0 ; Replace NULL codes with space codes
JNZ DISP23
MOV AL,' '
DISP23: CMP AL,'$' ; Finished if it is a '$'
JE DISP24
MOV DL,AL
MOV AH,2
INT 21H
LOOP DISP22 ; Repeat until finished
DISP24: RET
;
;****************************************************************************;
;
; DISPEXT - Display The File Name Extension
;
; This routine assembles and displays the file name extension.
;
; Entry: None
;
; Exit: None
;
; Alters: All registers are altered
;
;****************************************************************************;
;
DISPEXT:
MOV AH,2 ; Add a space before the extension
MOV DL,' '
INT 21H
MOV CX,3 ; Display up to 3 symbols of extension
; Display the sub-directory extension
DISPX1: LODSB
CMP AL,'.'
JE DISPX1 ; Ignore the period if still here
CMP AL,0 ; Quit when 0 is found
JNZ DISPX2
MOV AL,' ' ; Write a space instead of a zero
DISPX2: MOV DL,AL ; Write the next symbol
MOV AH,2
INT 21H
LOOP DISPX1
RET
;
;****************************************************************************;
;
; Check DOS version and return it in AL
;
; This routine fetches the version of DOS that is currently being used.
;
; Entry: None
;
; Exit: AL contains the version, 2, 3 etc.
;
; Alters: All registers are altered
;
;****************************************************************************;
;
CHKDOS: MOV AH,30H ; Fetch DOS version
INT 21H ; Call DOS
AND AL,07H ; Discard unused upper bits
RET
;
;****************************************************************************;
;
; GET_ARGS - Get Command Line Arguments
;
; Entry: None
;
; Exit: The ASCII number is in NDAYS.
; The drive is in DRIVE.
; The directory is in DIREC.
;
; The Carry flag is set if there is an error in the arguments.
;
; Alters: All registers are altered
;
;****************************************************************************;
;
GET_ARGS:
MOV SI,CMDLINE
MOV CH,0
LODSB
MOV CL,AL ; Length of args in CX
CMP AL,0
JZ GA8 ; Skip to return if no arguments
CALL CHKDOT ; See if arg list contains '.'
LODSB
DEC CX
JCXZ GA8 ; Return if no more symbols in argument list
CMP AL,'/'
JNE GA2 ; Skip if not a slash
; Pick up the number of days from the cmd line
MOV BX,0
GA1: LODSB ; Get next symbol
DEC CX
CMP AL,CR
JE GA8 ; Branch to return if end of the args
CMP AL,' '
JE GA2 ; Skip if end of the number
CMP AL,'0'
JL GA5 ; Skip if < '0'
CMP AL,'9'
JG GA5 ; Skip if > '9'
SUB AL,30H ; Convert to a hex number
MOV NDAYS[BX],AL ; Store this digit of the number of days
JCXZ GA8 ; Return if no more symbols
INC BX
CMP BX,4 ; Max number of digits
JL GA1 ; Loop for next digit if okay yet
LODSB ; Pick up the next symbol
DEC CX
CMP AL,CR
JE GA8 ; Branch to return if end of the args
CMP AL,' '
JNE GA5 ; Branch to report error if not a space
; Skip over any spaces
GA2: CMP AL,' '
JNE GA3 ; Skip if not a space
JCXZ GA8 ; Return if no more symbols
MOV DI,SI
MOV AL,' '
REPE SCASB
DEC DI
MOV SI,DI
LODSB ; Pick up the next symbol
; Get the disk drive and see if it is valid
GA3: CMP BYTE PTR [SI],':'
JNE GA5 ; Branch if not a valid drive
AND AL,5FH ; Convert drive to upper case
CALL VAL_DRIVE
JC GA6 ; Branch to return if not a valid drive
MOV DRIVE,AL ; Store the drive letter
; Pick up the directory if it is in the cmd line args
INC SI ; Point to the '\'
CMP BYTE PTR [SI],'\'
JNE GA8 ; Finished if no directory
MOV CX,MAXLEN-2
INC SI
MOV DI,OFFSET DIREC
GA4: LODSB ; Get the directory
CMP AL,CR
JE GA8
STOSB ; Store the directory & filespec
LOOP GA4
JMP SHORT GA8 ; Finished so return
; Report invalid arguments
GA5: MOV AH,9
MOV DX,OFFSET ERMSG2
INT 21H
INC BYTE PTR ERRFLG
GA6: STC
RET ; Return after error
; Now need to assemble the number of days since 1-Jan-1980
GA8: CALL GET_DAYS ; SI points to the next symbol
RET ; Return to calling routine
;
;****************************************************************************;
;
; CHKDOT - Check for a '.' in the argument list
;
; Entry: CX = Length of argument list to scan
; SI = Start of argument list to scan
;
; Exit: Byte variable HASDOT = 0 if a '/./' is not found in the arg list.
; Byte variable HASDOT = 1 if a '/./' is found in the arg list.
;
; Alters: Only the flag register is altered
;
CHKDOT: PUSH CX ; Save registers
PUSH DI
PUSH AX
MOV BYTE PTR HASDOT,0; Initially clear the flag
MOV AL,'.'
MOV DI,SI
REPNE SCASB ; Scan for '.'
JNE CHKDOT1
MOV BYTE PTR HASDOT,1; Set flag since '.' was found
CHKDOT1:POP AX ; Restore registers
POP DI
POP CX
RET
;
;****************************************************************************;
;
; GET_DAYS - Convert the command line input in NDAYS from hex bytes to a
; hex number of days in HDAYS.
;
; Entry: None
;
; Exit: None
;
; Alters: Only the flag register is altered.
;
;****************************************************************************;
;
GET_DAYS:
PUSH AX ; Save registers
PUSH BX
PUSH CX
PUSH DI
PUSH SI
; Convert from NDAYS to the one word hex number in HDAYS
GD2: MOV SI,OFFSET NDAYS
; NDAYS contains four "decimal" numbers - need hex to get COMDAYS
; Move the 4 decimal digits to TEMP, right shifted
MOV SI,OFFSET NDAYS
MOV AH,4
GD3: CMP BYTE PTR [SI],' '
JE GD5 ; Done if space code in NDAYS
MOV DI,OFFSET TEMP ; Point to temporary buffer
MOV CX,3
GD4: MOV AL,[DI+1] ; Left shift the bytes in the buffer
STOSB
LOOP GD4
LODSB ; Get next digit from NDAYS
STOSB ; Store it right shifted in temporary buffer
DEC AH
JNZ GD3 ; Repeat until space is found in NDAYS
; Convert 4 decimal digits in TEMP to one hex word in HDAYS
GD5: MOV SI,OFFSET TEMP ; Input buffer
MOV DI,OFFSET HDAYS ; Output buffer
LODSW ; Upper 2 decimal digits
XCHG AL,AH ; First digit in AH, second in AL
AAD ; Convert two digits to hex in AL
MOV CL,100 ; Multiplier
MUL CL ; Multiply by 100 decimal (64 hex)
MOV DX,AX ; Save first two hex digits in DX
LODSW ; Lower 2 decimal digits
XCHG AL,AH ; Third digit in AH, fourth in AL
AAD ; Convert two digits to hex in AL
ADD AX,DX ; Add third & fourth digits to first two
STOSW ; Save HDAYS
GD6: MOV AX,SYSDAYS
SUB AX,HDAYS ; COMDAYS = SYSDAYS - HDAYS
JG GD7 ; Branch if > 0 (1 = 1-Jan-80)
MOV AX,1 ; Limit COMDAYS to 1-Jan-80
GD7: MOV COMDAYS,AX
CALL UNHDATE ; Place COMDAYS in the message
POP SI ; Restore registers
POP DI
POP CX
POP BX
POP AX
RET ; Return to caller
;
;****************************************************************************;
;
; GET_SYSDATE - GET SYSTEM DATE
;
; This routine fetches the System date & time and stores it in the buffer.
;
; Entry: DI = Offset of the hex buffer to store it in.
;
; DOS function 2Ah returns the system date as:
;
; CX = Year (1980 through 2099)
; DH = Month (1 through 12)
; DL = Day (1 through 31)
;
;
; DOS function 2Ch returns the system time as:
;
; CH = Hour (0 through 23)
; CL = Minutes (0 through 59)
; DH = Seconds (0 through 59)
; DL = Hudredths of seconds (0 through 99)
;
; Exit: The System date is stored in the buffer in three hex values
; as YYMMDD.
;
; Alters: All registers are altered.
;
;****************************************************************************;
;
GET_SYSDATE:
MOV AH,2AH ; Get the system date
INT 21H
; CX = Year (1980 through 2099)
; DH = Month (1 through 12)
; DL = Day (1 through 31)
SUB CX,1980
MOV BYTE PTR [DI+0],CL
MOV BYTE PTR [DI+1],DH
MOV BYTE PTR [DI+2],DL
MOV AH,2CH ; Get the system time
INT 21H
; CH = Hour (0 through 23)
; CL = Minutes (0 through 59)
; DH = Seconds (0 through 59)
; DL = Hundredths of seconds (0 through 99)
MOV BYTE PTR [DI+3],CH
MOV BYTE PTR [DI+4],CL
MOV BYTE PTR [DI+5],DH
MOV BYTE PTR [DI+6],DL
RET
; ;
;****************************************************************************;
; ;
; HDATE - Convert A Date To A Hex Number Of Days Since 1-Jan-1980 ;
; ;
; Entry: SI = Offset of the date to convert. ;
; The date to convert is in a 3 byte buffer as YYMMDD. ;
; DI = Offset of the buffer to store the result in. ;
; ;
; Exit: The date is stored in a one word hex number of the ;
; the number of days since 1-Jan-1980. ;
; The first byte is the least significant, the second ;
; byte is the most significant. ;
; ;
; Alters: All registers are altered. ;
; ;
;****************************************************************************;
; 1 2 3 4 5 6 7 8 9 10 11 12
DAY DB 0,31,28,31,30,31,30,31,31,30,31,30,31 ; Days in each month
; SI points to the year
; SI+1 points to the month
; SI+2 points to the day of the month
HDATE: MOV AL,[SI+2] ; Get the day of this month
MOV AH,0
MOV [DI],AX ; Put it in the buffer
MOV BYTE PTR DAY+2,28
MOV AL,[SI] ; Get the year
AND AL,03H ; Check for leap year
JNZ HD2 ; Skip if not leap year
INC BYTE PTR DAY+2 ; Add one to February's days
HD2: MOV AH,0
MOV AL,[SI+1] ; This month in AX
DEC AX ; Previous month
JLE HD6 ; Skip if this month is Jan
HD3: PUSH AX ; Save month
MOV BX,AX ; Month for index
MOV AL,DAY[BX] ; Days in the month
MOV AH,0
ADD WORD PTR [DI],AX; Add the days in this month to total
POP AX
DEC AX
JNZ HD3 ; Repeat for all earlier months
; Now have the days so far this year - need days of all other years since 80
HD6: MOV DL,[SI] ; Get the current year
DEC DL ; Get last year
JL HD12 ; Done if this is 1980
; Loop for each year since 1980
HD8: MOV AL,DL ; Get the year
MOV CX,365 ; Number of days in a year
AND AL,03H ; Check for leap year
JNZ HD9 ; Skip if not leap year
INC CX ; Add one to the year's days
; Add the number of days in the year to the buffer
HD9: ADD WORD PTR [DI],CX
DEC DL
JGE HD8 ; Loop for the next year - Done if negative
HD12: RET
;
;****************************************************************************;
;
; GET_FILDATE - GET FILE DATE & TIME
;
; This routine gets the file date & time from the FCB after the DOS
; Find First or Find Next function has been executed.
;
; Entry: DI = Offset of the hex buffer to store the date & time in.
;
; Exit: The file date & time is stored in the hex buffer as:
; YYMMDDHHMMSS
; The file date & time is stored in the ASCII buffer as:
; 'MM/DD/YY HH:MM:SS'
;
; Alters: All registers are altered.
;
; The File Time & Date are obtained from the file FCB as follows:
;
; Time - FCB bytes 22 & 23
; Bits 11-15 = Hours (0 through 23)
; Bits 05-10 = Minutes (0 through 59)
; Bits 00-04 = Number of 2 second increments (0 through 29)
;
; Date - FCB bytes 24 & 25
; Bits 09-15 = Year (Relative to 1980)
; Bits 05-08 = Month (0 through 12)
; Bits 00-04 = Day of month (0 through 31)
;
;****************************************************************************;
;
GET_FILDATE:
; Date = FCB Bytes 24-25
; Bits 09-15 = Year (Relative to 1980)
MOV DI,OFFSET FILDATE
MOV AL,FSPEC+25
MOV DH,AL
SHR AL,1
AND AL,7FH
STOSB ; Store year in hex buffer
ADD AL,80 ; Want two-digit year
CMP AL,99 ; Check for greater than 99
JLE GF1 ; Skip if not greater than 99
SUB AL,100 ; Use "01" for 2001, "11" for 2011, etc.
GF1: CALL HEX_DEC2 ; Convert year into two decimal digits
MOV SI,OFFSET ADATE
IF DTYPE
MOV [SI+7],AX ; Store year in ASCII string
ELSE
MOV [SI+6],AX ; Store year in ASCII string
ENDIF
; Bits 05-08 = Month (0 through 12)
MOV AL,FSPEC+24
MOV AH,DH
SHR AX,1
AND AX,0F0H
SHR AL,1
SHR AL,1
SHR AL,1
SHR AL,1
STOSB ; Store month in hex buffer
IF DTYPE
DEC AL ; Month of 0 - 11 for index
MOV AH,AL ; Put the month in AH
ADD AL,AL ; Multiply month by three for index
ADD AL,AH ; Month times three
MOV AH,0
MOV CX,3 ; Length of the month text
PUSH DI ; Save these registers
PUSH SI
MOV DI,SI
ADD DI,3 ; Point to the place in the string
MOV SI,OFFSET MONTH ; Table of months (Jan, Feb, etc.)
ADD SI,AX
REP MOVSB ; Store the month in ASCII string
POP SI ; Now restore these registers
POP DI
ELSE
CALL HEX_DEC2
CMP AL,'0'
JNE GF2
MOV AL,' ' ; Suppress leading 0 in month
GF2: MOV [SI],AX ; Store the month in ASCII string
ENDIF
; Bits 00-04 = Day of month (0 through 31)
MOV AL,FSPEC+24
AND AL,1FH
STOSB ; Store day in hex buffer
CALL HEX_DEC2
IF DTYPE
CMP AL,'0' ; Suppress leading zero in day
JNE GF2
MOV AL,' '
GF2: MOV WORD PTR [SI],AX; Store day in ASCII string
ELSE
MOV [SI+3],AX ; Store day in ASCII string
ENDIF
; Time - FCB Bytes 22-23
; Bits 11-15 = Hours (0 through 23)
MOV DI,OFFSET FILDATE+3
MOV AL,FSPEC+23
AND AL,0F8H
SHR AL,1
SHR AL,1
SHR AL,1
STOSB ; Store hours in hex buffer
CALL HEX_DEC2 ; Convert to two decimal ASCII symbols
MOV SI,OFFSET ATIME
MOV [SI],AX ; Store hours in ASCII string
; Bits 05-10 = Minutes (0 through 59)
MOV AL,FSPEC+22
MOV AH,FSPEC+23
SHR AX,1
SHR AX,1
SHR AX,1
SHR AX,1
SHR AX,1
AND AX,3FH
STOSB ; Store minutes in hex buffer
CALL HEX_DEC2
MOV [SI+3],AX ; Store minutes in ASCII string
; Bits 00-04 = Number of 2 second increments (0 through 29)
MOV AL,FSPEC+22
AND AL,1FH
SHL AL,1 ; Multiply by 2 for actual seconds
STOSB ; Store seconds in hex buffer
CALL HEX_DEC2
MOV [SI+6],AX ; Store seconds in ASCII string
RET
; ;
;****************************************************************************;
; ;
; CONVERT HEX TO DECIMAL ASCII VERSION 8/25/89 ;
; ;
; Convert from 2 hex digits in AL to 2 decimal ASCII symbols in AX. ;
; (Sometimes called BCD, but other things are also called BCD) ;
; ;
; ENTRY: AL = The number to convert (00 to 63 hex, 0 to 99 dec). ;
; ;
; EXIT: AH = Least significant decimal ASCII symbol ;
; AL = Most significant decimal ASCII symbol ;
; as required for writing to the display ;
; Carry is set if the input number is out of range. ;
; ;
; ALTERS: All registers except CX & DX should be considered altered. ;
; ;
;****************************************************************************;
; ;
HEX_DEC2:
CMP AL,99
JLE H_D2 ; Skip if number is okay
STC ; Set carry flag for error
JC H_D3 ; Exit if number is out of range
H_D2: AAM ; Convert two digits to decimal in AX
XCHG AL,AH ; Lower digit in AH, Upper in AL
ADD AX,3030H ; Convert to ASCII
CLC ; Clear error flag
H_D3: RET ; Return to calling routine
; ;
;****************************************************************************;
; ;
; Convert Hex To Decimal Ascii Version 8/31/89 ;
; ;
; Copyright (C) John Pulliam 1989 ;
; ;
; Convert from 6 hex digits pointed to by SI to 8 decimal ASCII ;
; symbols in the string pointed to by DI. ;
; ;
; ENTRY: SI = Offset of number to convert (LSW, MSW) where the ;
; words are arranged LSB, MSB. ;
; The maximum input value is 83,886,079 or 4FFFFFF hex. ;
; DI = Offset of ASCII decimal result. ;
; ;
; EXIT: The decimal ASCII symbols are stored in high to low order ;
; as required for writing to the display ;
; The output buffer must be large enough to contain the results.;
; ;
; An error is reported to the CRT if the dividend is too large ;
; and a return is made with the carry flag set. ;
; ;
; ALTERS: All registers should be considered altered. ;
; ;
; NOTE: The main program must provide the variable, "TEN DW 10". ;
; ;
; Example: Convert 927C0 to 600,000 decimal ASCII. ;
; 600,000 = 9*65536 + 10176 ;
; ;
; HSIZE DW 27C0H, 9 ;
; DSIZE DB 8 DUP (0) ;
; ;
; MOV SI,OFFSET HSIZE ;
; MOV DI,OFFSET DSIZE ;
; CALL HEX_DEC8 ;
; ;
;****************************************************************************;
; ;
DFLAG DB 0 ; Flag for possible overflow
CRFLG DB 0 ; Carry flag
ODD DB 7 DUP (0) ; Odd number flag
DIVOV DB CR,LF,7,'Dividend Too Large',CR,LF,'$'
HEX_DEC8:
PUSH DI ; Save buffer pointer
PUSH DI ; Save working register
MOV CX,8
MOV AL,0
REP STOSB ; Clear the result buffer
POP DI ; Restore buffer pointer
; Check for valid dividend
CMP WORD PTR [SI+2],1280
JL H_D81 ; Branch if valid
MOV AH,9 ; Report invalid dividend error
MOV DX,OFFSET DIVOV
INT 21H
STC ; Set carry flag
JMP H_D89 ; Quit after reporting the error
; Valid dividend so process it
H_D81: MOV DFLAG,0 ; Clear the possible-overflow flag
PUSH DI
MOV CX,7
MOV DI,OFFSET ODD
MOV AL,0
REP STOSB ; Clear the odd-number flags
POP DI
MOV CX,8 ; Size of the output buffer
; Put the hex number to convert in DX,AX & set up buffer pointer
LODSW ; Lower hex word
MOV DX,[SI] ; Upper hex word
ADD DI,CX
DEC DI ; Point to right end of the result buffer
PUSH CX ; Save buffer length and pointer
PUSH DI ; for multiply by 2 later
; Prevent Divide Overflow if input is greater than 655359 by dividing
; it by two enough times then multiplying the result by two the same
; number of times.
H_D82: CMP DX,10 ; See if greater than 655359
JL H_D83 ; Skip if not
MOV BH,0
MOV BL,DFLAG ; Index for ODD flags
SHR AX,1 ; Divide the original number by two
ADC ODD[BX],0 ; Save if number was odd
MOV BX,DX
AND BX,1 ; Get bit 16 of the input
ROR BX,1 ; Rotate into bit 15 position
OR AX,BX ; Insert bit 15 into AX
SHR DX,1 ; Divide upper word by two
INC DFLAG ; Set flag so we double the result
JMP H_D82
; Hex to decimal/ascii conversion loop
; Divide the number by ten
H_D83: DIV TEN ; Divide for the next decimal digit
ADD DL,30H ; Convert remainder to ASCII symbol (< 10)
MOV [DI],DL ; Store the ASCII symbol
DEC DI ; Move buffer pointer left
MOV DX,0 ; Clear upper word
LOOP H_D83 ; Branch to convert all hex digits
; See if we need to double the end result
H_D84: POP DI ; Get pointer to right end of the buffer
POP CX ; Get buffer length
CMP DFLAG,0 ; 0 = finished - don't double the result
JZ H_D88 ; Branch when finished
MOV BX,0 ; Initialize ODD index
; Loop here for each time it is necessary to double the end result
H_D85: PUSH CX ; Save buffer length
PUSH DI ; Save buffer pointer
MOV CRFLG,0 ; Clear the carry flag
; Multiply the end result by two
; Loop here doing the multiply by 2
H_D86: MOV AL,[DI] ; Get a symbol
SUB AL,30H ; Convert to a number
SHL AL,1 ; Multiply the number by two
ADD AL,ODD[BX] ; Add one if number was odd before divide by 2
MOV ODD[BX],0 ; Clear the ODD flag for this number
ADD AL,CRFLG ; Add any carry from the previous multiply
MOV CRFLG,0 ; Clear the carry for this symbol
CMP AL,10 ; Check for a carry this time
JL H_D87 ; Branch if no carry this time
MOV CRFLG,1 ; Set the carry flag for next time
SUB AL,10 ; Subtract after carrying
H_D87: ADD AL,30H ; Convert back to ASCII
MOV [DI],AL ; Re-store the ASCII symbol
DEC DI ; Point to the next symbol
LOOP H_D86 ; Repeat for all symbols
POP DI ; Get pointer to right end of the buffer
POP CX ; Get buffer length
INC BX
DEC DFLAG ; Decrement loop counter
JG H_D85 ; Repeat until finished
; Suppress leading zeros of result then return to calling routine
H_D88: CLC ; Clear the error flag
H_D89: POP DI ; Get start of buffer again
PUSHF ; Save the Carry flag for error flag
CALL SUPPRESS ; Suppress leading zeros from the result
POPF ; Restore error flag
RET ; Return to calling routine
; ;
;****************************************************************************;
; ;
; This routine suppresses leading zeros in a buffer by replacing them with ;
; null codes ;
; ;
; Entry: DI = start of the 8 digit buffer. ;
; ;
; Exit: The leading zeros in the buffer have been replaced by null codes. ;
; ;
; Alters: All registers should be considered altered. ;
; ;
;****************************************************************************;
; ;
SUPPRESS:
MOV CX,7 ; Max number of digits to suppress
SUP2: CMP BYTE PTR [DI],'0'
JNE SUPRET ; Quit when non-zero is found
MOV BYTE PTR [DI],0 ; Store null code
INC DI ; Move pointer
LOOP SUP2 ; Repeat until done
SUPRET: RET
;
;****************************************************************************;
;
; FINDFILE - FIND FIRST OR NEXT FILE
;
; Find the first or the next file that matches the filespec.
;
; Entry: The desired filespec must be in FULLNAM in ASCIIZ format.
;
; Exit: Returns the next existing file name in FSPEC+30, 12 bytes long max.
; Carry flag is set if there are no more matching files or if the
; specified directory doesn't exist.
; AX = 12H if there was no matching file.
;
; Alters: All registers are altered.
;
;****************************************************************************;
;
FINDFILE:
MOV DX,OFFSET FULLNAM; Must contain file spec in ASCIIZ format
MOV AH,FUNC ; Either find "FIRST" or "NEXT" file
MOV BYTE PTR FUNC,NEXT
; Select the desired file attributes
MOV CX,RO + HDN + SYS + VOL + DIR
INT 21H ; Returns file name in FSPEC+30
PUSHF ; Save the carry flag
JNC FF4 ; Branch if okay
CMP AX,12H ; Check for no more files
JE FF4 ; Branch if no more files
; Report invalid directory
PUSH AX ; Save the DOS error code
MOV DX,OFFSET ERMSG9; Point to the error message
MOV AH,9
INT 21H ; Display the error message
INC BYTE PTR ERRFLG ; Increment the error return code
POP AX ; Retrieve the DOS error code
FF4: POPF ; Retrieve the DOS carry flag
RET ; Return to calling routine
PAGE
;
;****************************************************************************;
;
; VAL_DRIVE - Check for a valid disk drive
;
; Entry: AL contains the drive letter.
;
; Exit: Carry is set if the drive is not valid.
;
; Alters: Only the Flag register is altered.
;
;****************************************************************************;
;
; Verify that the input file spec of "d:" is a valid drive
VAL_DRIVE:
PUSH AX ; Save working registers
PUSH CX
PUSH DX
PUSH DI
PUSH SI
AND AL,0DFH ; Allow either upper or lower case
CMP AL,'A' ; Check for legal range of drives
JL VALD2 ; Skip if invalid drive
PUSH AX ; Save the drive letter
SUB AL,40H ; Drive A = 1, etc.
MOV DL,AL
MOV AH,36H ; Verify that it is a valid disk drive
INT 21H
CMP AX,-1 ; DOS returns -1 if not a valid drive
POP AX
JE VALD2 ; Branch if invalid drive
CLC ; Clear the carry flag
JNC VALD3 ; Branch to return
; Report invalid drive error
VALD2: MOV DX,OFFSET ERMSG8; Invalid disk drive
MOV AH,9 ; Display WRITE function
INT 21H ; Call DOS
MOV AL,-1 ; Error completion flag
INC BYTE PTR ERRFLG ; Inc error flag
STC ; Set Carry for error
VALD3: POP SI ; Restore all of the registers
POP DI
POP DX
POP CX
POP AX
RET ; Return to calling routine
;
;****************************************************************************;
;
; FREE_SPACE - Get the free space on a drive.
;
; Entry: DL = the drive to get the free bytes for.
; SI points to the two word hex result buffer.
; DI points to the eight byte decimal ascii result buffer.
;
; Exit: The result is placed in the external word variable, FREESIZ,
; in two words, LSW, MSW.
; The carry flag is set if an error occurs.
;
; Alters: All registers are altered.
;
;****************************************************************************;
;
FREE_SPACE:
MOV AH,36H ; Verify that it is a valid disk drive
INT 21H
CMP AX,-1 ; DOS returns -1 if not a valid drive
JE FS3 ; Skip if invalid drive
; Multiply (Sectors/Cluster) * (Free Clusters) * (Bytes/Sector)
FS2: MUL BX ; Sectors per cluster times
; number of free clusters times
MUL CX ; number of bytes per sector
MOV [SI],AX ; Least significant word
MOV [SI+2],DX ; Most significant word
CALL HEX_DEC8 ; Get total bytes in decimal
JNC FS4 ; Branch to return
; Set error flag if error
FS3: INC BYTE PTR ERRFLG ; Increment the error flag
STC ; Set carry for error flag
FS4: RET ; Return to calling routine
;
;****************************************************************************;
;
; UNHDATE - Unpack A Hex Date.
;
; Entry: The date to unpack is in COMDAYS.
;
; Exit: The result is placed in the external byte variable, SINCE,
; suitable for writing to the display.
;
; Alters: All registers are altered.
;
; Note: The external byte buffer, DAY, must be provided.
;
;****************************************************************************;
;
UNHDATE:
MOV DAY+2,28 ; Initialize days in February
MOV DX,COMDAYS
MOV BL,0 ; Initial year relative to 1980
MOV CX,365 ; Days in most years
UNH1: MOV DI,365 ; Days in most years
MOV AL,BL ; The year relative to 1980
AND AL,03H ; Leap year if zero
JNZ UNH2 ; Skip if not leap year
INC DI ; Increment for leap year
INC CX ; Increment total days if leap year
UNH2: CMP CX,DX ; See if we overshot COMDAYS
JGE UNH4 ; Branch if COMDAYS is this year
; Equal if Dec 31st.
ADD CX,365 ; Increment total number of days
; CX increments later if leap year
INC BL ; Increment to the next year
JMP UNH1 ; Loop until less than a year
; Now BL = year of COMDAYS
UNH4: SUB CX,DI ; Adjust count of days
MOV AH,0
XCHG AL,BL ; Year into AX, leap year mask in BL
ADD AX,80 ; Want two-digit year
AAM ; Make year into two decimal digits
CMP AH,9 ; What if it's greater than 99 ?
JLE UNH5
SUB AH,10 ; Use "01" for 2001, "11" for 2011, etc.
UNH5: ADD AX,3030H ; Make it ASCII
IF DTYPE
MOV SINCE+7,AH ; Save year in message
MOV SINCE+8,AL
ELSE
MOV SINCE+6,AH ; Save year in message
MOV SINCE+7,AL
ENDIF
AND BL,03H ; Zero if leap year
SUB BL,1
ADC DAY+2,0 ; Increment days in Feb if leap year
MOV SI,1 ; Index into days per month
UNH6: MOV AH,0
MOV AL,DAY[SI] ; AX is the days in this month
ADD CX,AX
CMP CX,DX
JGE UNH8 ; Branch when we've passed it
INC SI
JMP UNH6 ; Loop for another year
UNH8: SUB CX,DX
SUB AX,CX ; SI = Month, AX = the day of the month
MOV AH,0
CALL HEX_DEC2 ; Make it into ASCII decimal
IF DTYPE
CMP AL,'0' ; Suppress leading zero in day
JNE UNH9
MOV AL,' '
UNH9: MOV WORD PTR SINCE,AX; Save day in message
DEC SI ; Month of 0 - 11 for index
MOV AX,SI ; Get the month
ADD AX,AX ; Multiply month by three for index
ADD AX,SI ; Month times three
MOV CX,3
MOV SI,OFFSET MONTH ; Table of months (Jan, Feb, etc.)
ADD SI,AX
MOV DI,OFFSET SINCE+3
REP MOVSB ; Store the month
ELSE
MOV WORD PTR SINCE+3,AX; Save day in message
MOV AX,SI ; Get the month
MOV AH,0
CALL HEX_DEC2 ; Make it into ASCII decimal
CMP AL,'0' ; Suppress leading zero in month
JNE UNH9
MOV AL,' '
UNH9: MOV WORD PTR SINCE,AX; Save month in message
ENDIF
RET ; Return to caller
SUBTTL Messages and Data Storage
PAGE +
; MESSAGES and DATA STORAGE
; Informative messages
COPY DB 'Copyright (c) 1989, 1990, 1991 by J.R. Pulliam'
SMSG1 DB CR,LF,'NEW - Version 10/15/91 - J. Pulliam'
DB CR,LF,'$'
; THESE ARE AN ORDERED SET - DO NOT RE-ARRANGE THEM
SMSG2 DB CR,LF,'Directory of '
DRIVE DB ' :\'
DIREC DB MAXLEN DUP (0)
DB ' since 00:00, '
IF DTYPE
SINCE DB 'DD-Mmm-YY',CR,LF,LF,'$' ; Could include the time?
MONTH DB 'JanFebMarAprMayJunJulAugSepOctNovDec'
ELSE
SINCE DB 'MM/DD/YY',CR,LF,LF,'$' ; Could include the time?
ENDIF
; File size, date & time
; THESE ARE AN ORDERED SET - DO NOT RE-ARRANGE THEM
FSIZE DB ' ',0,0,0,0,0,0,0,0,' '
IF DTYPE
ADATE DB 'DD-Mmm-YY '
ELSE
ADATE DB 'MM-DD-YY '
ENDIF
ATIME DB '00:00:00 '
ATTS DB ' R-O SYS ARC HDN VOL DIR',CR,LF,'$'
ATT_TXT DB ' R-O HDN SYS VOL DIR ARC'
; THESE ARE AN ORDERED SET - DO NOT RE-ARRANGE THEM
SMSG3 DB CR,LF,' Total of '
TOTS DB 8 DUP (0),' bytes in '
TOTF DB 8 DUP (0),' file'
TOTFS DB 's',CR,LF,'$'
TOTFILE DW 0,0
TOTSIZE DW 0,0
SMSG4 DB CR,LF,' Total of '
SIZLEFT DB ' bytes free',CR,LF,'$'
FREESIZ DW 0,0
; Error messages
ERMSG1 DB CR,LF,LF,7,'*** SORRY - REQUIRES DOS 2.0 OR HIGHER ***'
DB CR,LF,LF,'$'
ERMSG2 DB CR,LF,7,'*** INVALID ARGUMENTS ***',CR,LF,'$'
ERMSG8 DB CR,LF,7,'*** INVALID DRIVE *** ',CR,LF,'$'
ERMSG9 DB CR,LF,7,'*** INVALID DIRECTORY *** ',CR,LF,'$'
ERRFLG DB 0 ; 0 = Normal completion
; Miscellanious variables
TEN DW 10 ; Divisor for conversion to decimal
FUNC DB FIRST ; DOS functions - Find FIRST or NEXT file
HASDOT DB 0 ; 1 if '.' is in argument list
DIRFLG DB 0 ; Directory/subdirectory flag
SYSDATE DB 0,0,0,0,0,0,0
FILDATE DB 0,0,0,0,0,0,0
COMDAYS DW 0 ; Days (since 1-Jan-1980) to compare against
SYSDAYS DW 0 ; System days since 1-Jan-1980
FILDAYS DW 0 ; File days since 1-Jan-1980
NDAYS DB ' '
HDAYS DW 0
TEMP DB 0,0,0,0
; Disk Transfer Buffers & Related Items
FSPEC DB 30 DUP (' ') ; DTA for FIND FIRST/NEXT function
FILENAM DB 12 DUP (' ') ; File name from DOS-2 FIND FIRST/NEXT function
DB 0,'$'
FULLNAM DB ' :\',65 DUP (0),5 DUP (0)
DOT DB '. $' ; Dot directory name
DOTDOT DB '.. $' ; Two dot directory name
DIRNAME DB ' <DIR>$'
CSEG ENDS
END NEW